'''
应用工厂:在一个函数内部创建Flask实例来代替创建全局实例的函数,所有应用相关的配置、注册和其他设置都会在函数内部完成,然后返回这个应用.
__init__.py 有两个作用:一是包含应用工厂;二是flaskr文件夹应当视作为一个包.
'''
import os

from flask import Flask


def create_app(test_config=None) -> Flask:
    '''
    create_app 是一个应用工厂函数
    '''
    app = Flask(__name__, instance_relative_config=True)
    # __name__ 是当前 Python 模块的名称。应用需要知道在哪里设置路径,使用 __name__ 是一个方便的方法。
    # instance_relative_config=True 告诉应用配置文件是相对于实例文件夹的相对路径.实例文件夹在flaskr包的外面,用于存放本地数据(例如配置密钥和数据库),不应当提交到版本控制系统。
    app.config.from_mapping(
        # 设置一个应用的缺省配置
        SECRET_KEY='dev',
        # SECRET_KEY 是被 Flask 和扩展用于保证数据安全的.在开发过程中,为了方便可以设置为 'dev',但是在发布的时候应当使用一个随机值来重载它。
        DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),
        # DATABASE SQLite 数据库文件存放在路径.它位于 Flask 用于存放实例的 app.instance_path 之内.
    )

    if test_config is None:
        # 使用 config.py 中的值来重载缺省配置,如果 config.py 存在的话.例如,当正式部署的时候,用于设置一个正式的 SECRET_KEY.
        app.config.from_pyfile('config.py', silent=True)
    else:
        # test_config 也会被传递给工厂,并且会替代实例配置.这样可以实现测试和开发的配置分离,相互独立
        app.config.from_mapping(test_config)

    try:
        os.makedirs(app.instance_path)
        # os.makedirs()可以确保app.instance_path存在。Flask不会自动创建实例文件夹,但是必须确保创建这个文件夹,因为SQLite数据库文件会被保存在里面。
    except OSError:
        pass

    # @app.route() 创建一个简单的路由,这样在继续教程下面的内容前你可以先看看应用如何运行的.它创建了URL/hello和一个函数之间的关联.这个函数会返回一个响应,即一个 'Hello, World!' 字符串.
    @app.route('/hello')
    def hello():
        return 'Hello, World!'

    # 在工厂中导入并调用注册函数.
    from . import db
    db.init_app(app)

    # 使用 app.register_blueprint() 导入并注册蓝图.
    from . import auth
    app.register_blueprint(auth.bp)

    from . import blog
    app.register_blueprint(blog.bp)
    app.add_url_rule('/', endpoint='index')
    # 与验证蓝图不同,博客蓝图没有 url_prefix .因此 index 视图会用于 / , create 会用于 /create ,以此类推.博客是 Flaskr 的主要功能,因此把博客索引作为主索引是合理的.
    # 但是,blog 的 index 视图的端点会被定义为 blog.index .一些验证视图会指定向普通的 index 端点. 我们使用 app.add_url_rule() 关联端点名称 'index' 和 /URL,这样url_for('index')或 url_for('blog.index')都会有效,会生成同样的 /URL .
    # 在其他应用中,可能会在工厂中给博客蓝图一个 url_prefix 并定义一个独立的 index 视图,类似前文中的 hello 视图.在这种情况下 index 和 blog.index 的端点和 URL 会有所不同.
    return app
